package org.optionparser;

import java.util.List;
/**
 * OptionPrinter class, which is used for printing and customizing usage 
 * information for specified options 
 * 
 * @author Rastislav Kadlecek
 */
class OptionPrinter {

	
	
	/**
	 * The name of program (will be printed in usage information)
	 * If not specified, program name line will not be printed
	 */
	private String programName;
	/**
	 * Line containing program name and specified additional information
	 */
	private String programNameLine;
	/**
	 * Description of the separator character
	 */
	private String separatorDescription;
	/**
	 * Heading line for usage information
	 */
	private String heading;
	/**
	 * Specifies, if separator character and its description will
	 * be printed in usage information
	 */
	private boolean printSeparatorOption;
	/**
	 * Specifies, if heading line will be printed
	 */
	private boolean printHeading;
	/**
	 * Tabulator symbol
	 */
	private final String TAB = "\t";
	/**
	 * New line symbol
	 */
	private final String LINEBREAK = "\n";
	/**
	 * Space symbol
	 */
	private final String SPACE = " ";
	/**
	 * Comma symbol
	 */
	private final String COMMA_CHAR = ",";
	/**
	 * Equality Symbol
	 */
	private final String EQUALITY_CHAR = "=";
	/**
	 * Separator symbol
	 */
	private final String SEPARATOR = "--"; //prints as --
	
	
	/**
	 * Constructor, creates new instance of OptionPrinter class
	 * and sets default values
	 */
	public OptionPrinter()
	{
		//set default values
		this.programName = "";
		this.heading = "List of available options:";
		this.printHeading = true;
		this.separatorDescription = "Terminate option list.";
		this.printSeparatorOption = true;
		this.programNameLine = "[options] [arguments...]";
	}
	
	/**
	 * Prints usage information with specified options to System.out
	 * 
	 * @param definedOptions		List of specified options
	 */
	public void printOptions(List<Option> definedOptions)
	{
		//print program name line?
		if (!(this.programName.isEmpty()))
		{
			System.out.println(this.programNameLine + LINEBREAK);
		}
		//prints the usage information
		if (this.printHeading)
		{
			System.out.println(heading);
		}
		for (Option option : definedOptions)
		{
			String shortName = option.getShortName();
			String longName = option.getLongName();
			String paramName = option.getParameterName();
			String description = option.getDescription();
			printOption (shortName, longName, paramName, description);
		}
		if (this.printSeparatorOption)
		{
			printOption (SEPARATOR, "", "", this.separatorDescription);
		}
	}
	
	/**
	 * Prints the information about one specified option to System.out
	 * 
	 * @param shortName				Short name of option
	 * @param longName				Long name of option
	 * @param paramName				Parameter name
	 * @param description			Description of option
	 */
	private void printOption(String shortName, String longName, String paramName, String description)
	{
		StringBuilder sb = new StringBuilder(TAB);
		//append short name
		if (!(shortName.isEmpty()))
		{
			sb.append(shortName);
			if (!(paramName.isEmpty()))
			{
				sb.append(SPACE); 
				sb.append(paramName);
			}
		}
		//separator between short and long name
		if ((!(shortName.isEmpty()) && (!(longName.isEmpty()))))
		{
			sb.append(COMMA_CHAR);
			sb.append(SPACE);
		}
		//append long name
		if (!(longName.isEmpty()))
		{
			sb.append(longName);
			if (!paramName.isEmpty())
			{
				sb.append(EQUALITY_CHAR);
				sb.append(paramName);
			}
		}
		//print result
		String firstLine = sb.toString();
		System.out.println(firstLine);
		//if description is empty, do not print
		if (!(description.isEmpty())) {
			String secondLine = TAB + TAB + description;
			System.out.println(secondLine);
		}
	}

	/**
	 * Sets the value of the heading line
	 * Can be used f.e. for translation
	 * 
	 * @param heading			Value of Heading line
	 */
	public void setHeading(String heading) {
		this.heading = heading;
	}

	/**
	 * Sets the name of the program
	 * Program name line would be printed, only if valid program name
	 * is specified!
	 * 
	 * @param programName the programName to set
	 */
	public void setProgramName(String programName) {
		this.programName = programName;
		this.programNameLine = programName + SPACE + this.programNameLine;
	}

	/**
	 * Sets the value of line with program name (without program name)
	 * Program name line would be printed, only if valid program name
	 * is specified!
	 * 
	 * For example default value "[options] [arguments...]"
	 * prints
	 * "ProgramName [options] [arguments...]"
	 * 
	 * @param programNameLine 		The program name line
	 */
	public void setProgramNameLine(String programNameLine) {
		this.programNameLine = programNameLine;
	}

	/**
	 * Sets the description for the separator symbol
	 * Can be used f.e. for translation
	 * 
	 * @param separatorDescription 		Description of separator symbol
	 */
	public void setSeparatorDescription(String separatorDescription) {
		this.separatorDescription = separatorDescription;
	}

	/**
	 * Specifies, whether the separator (used to separate options and arguments),
	 * by default the -- symbol 
	 * should be also printed in list of options
	 * 
	 * @param printSeparatorOption 		If true, the separator WILL be printed, 
	 * 								if false, it WONT be printed
	 */
	public void setPrintSeparatorOption(boolean printSeparatorOption) {
		this.printSeparatorOption = printSeparatorOption;
	}

	/**
	 * Specifies, whether the heading line should be printed
	 * 
	 * @param printHeading 			If true, heading WILL be printed, 
	 * 								if false, it WONT be printed
	 */
	public void setPrintHeading(boolean printHeading) {
		this.printHeading = printHeading;
	}
	
	
	
	
}
